package com.trainsmart.smartmvc
{
	
	import com.trainsmart.smartmvc.conf.Action;
	import com.trainsmart.smartmvc.conf.Control;
	import com.trainsmart.smartmvc.conf.DAO;
	import com.trainsmart.smartmvc.conf.Flow;
	import com.trainsmart.smartmvc.conf.Property;
	import com.trainsmart.smartmvc.conf.Step;
	import com.trainsmart.smartmvc.conf.VO;
	import com.trainsmart.smartmvc.conf.View;
	
	import flash.events.Event;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.getDefinitionByName;
	
	import mx.core.UIComponent;
	
	public class SmartLoader  
	{
		
		private var _context:Context;		
		//public var mainConf:String = "com/trainsmart/smartmvc/module.xml";
		private var _root:UIComponent;
		
		private var func:Function;
		
		private var views:Array = new Array();
		private var controls:Array = new Array();
		private var daos:Array = new Array();
		private var vos:Array = new Array();
		private var flows:Array = new Array();
		
		public function SmartLoader(root:UIComponent)
		{
			_root = root;
			_context= new Context(_root);
			 
			 views = new Array();
			 controls = new Array();
			 daos = new Array();
			 vos = new Array();
			 flows = new Array();
		}
	    
	    
		/**
		 * uniqueId: 
		 * mainConf: configure xml file
		 * preLoad=Function(context:Icontext) : execute function before loading
		 * loadComplete=Function(context:Icontext) : execute function after loading
		 * 
		 */ 
		public function load(uniqueId:Number, mainConf:String, preLoad:Function=null, loadComplete:Function=null):void{			
			_context.registerContext(uniqueId);
			if(preLoad!=null)
				preLoad(_context);
			loadConfigure(mainConf);			
			func = loadComplete;
								
		}
		
		public function init():Context
		{
			_context.onload();
			return _context;	
		}
		
		
		/**
		 * load module configure from xml
		 * 
		 */ 
		private function loadConfigure(mainConf:String):void{
			
			var urlrequest:URLRequest = new URLRequest(mainConf);
			var urlloader:URLLoader = new URLLoader();
			urlloader.addEventListener(Event.COMPLETE,loadXML);		
			urlloader.load(urlrequest);
		}		
		private function loadXML(evt:Event):void{
			var urlloader:URLLoader=evt.target as URLLoader;
			var xml:XML = new XML(urlloader.data);				
			loadCaches(xml.caches.cache);
			loadDaos(xml.models.daos.dao);
			loadVos(xml.models.vos.vo);
			loadControls(xml.controls.control);			
			loadViews(xml.views.view);		
			loadFlows(xml.flows.flow);	
						
			onLoad();
			if(func!=null)
			  func(_context);
		}
		
		private function loadFlows(xmlflows:XMLList):void{
			/*
			<flow id="personflow">
			   <step id="personInfo" view="mainView">
					<action id="save" control="save"/>
					<action id="cancel" control="cancel"/>			
			   </step> 
			   <step id="successFlow" view="successView">			
					<action id="back" flow="personInfo" keepValue="true"/>
					<action id="close" control="close"/>			
			   </step> 
			   
			   <step id="cancelFlow" view="cancelView"> 
					<action id="back" flow="personInfo" keepValue="false"/>
					<action id="close" control="close"/>			
			   </step>	
		   </flow>
			*/
			var length:int = xmlflows.length();
			for(var n:int=0;n<length;n++){
				var xmlflow:XML = xmlflows[n];
				var flow:Flow = new Flow();
				flow.id = xmlflow.@id;
				flow.start = xmlflow.@start;
				flows[flow.id] = flow;
				var xmlsteps:XMLList =  xmlflow.child("step");
				for(var i:int=0;i<xmlsteps.length();i++){
					//<cache id="" referTo="" />				
					var xmlstep:XML =xmlsteps[i]; 
					var step:Step = new Step();
					step.id = xmlstep.@id;
					step.view = xmlstep.@view;
					flow.steps[step.id] = step;
					
					var xmlactions:XMLList = xmlstep.child("action");
					for(var j:int=0;j<xmlactions.length();j++){
							var a:Action = new Action();
							a.id = xmlactions[j].@id;
							a.name = xmlactions[j].@name;
							a.control = xmlactions[j].@control;
							a.step = xmlactions[j].@step;											
							step.actions[a.id] = a;					
					}					
				}		
			}
			
		
		}
		
		
		private function loadViews(views:XMLList):void{
			/*
			<view id="mainView" type="com.trainsmart.example.wizard.view.PersonView" vo="personvo">
				<property component="txtUserName" style="text" field="username" value=""/>
				<property component="txtFirstName" style="text" field="firstname"  value=""/>
				<property component="txtSurName" style="text" field="surname"  value=""/>
				<property component="txtBirth" style="text" field="birth"  value=""/>
			</view>
			*/
			var length:int = views.length();
			for(var i:int=0;i<length;i++){
				//<cache id="" referTo="" />				
				var view:XML = views[i];
				var v:View = new View();
				v.id = view.@id;
				v.type = view.@type;
				v.vo = view.@vo;
				//add property
				var properties:XMLList = view.child("property");
				for(var j:int=0;j<properties.length();j++){
						var p:Property = new Property();
						p.component = 	properties[j].@component;
						p.attribute = 	properties[j].@attribute;
						p.field = 	properties[j].@field;						
						v.properties.push(p);
				}
				this.views[v.id] = v;		
			}
		}
		
		private function loadCaches(caches:XMLList):void{
			var length:int = caches.length();
			for(var i:int=0;i<length;i++){
				//<cache id="" referTo="" />
				var entity:XML = caches[i];
				var key:String = entity.@id;
				var referTo:String = entity.@referTo;
				var paths:Array = referTo.split(".");
				var ui:UIComponent = _root;
				for(var j:int=0;j<paths.length;j++){
					var childUI:UIComponent = ui[paths[j]] as UIComponent;
					ui = childUI;
				}
				_context.putInSession(key,ui);
			}
		}
		
		private function loadVos(vos:XMLList):void
		{
			//<vo id="uservo" type="com.trainsmart.example.demo.model.UserVO"/>	
			var length:int = vos.length();
			for(var i:int=0;i<length;i++){
				/*
				<dao id="userdap" type="com.trainsmart.example.demo.model.UserDAO" vo="uservo"/>
				*/
				var entity:XML = vos[i];
				var vo:VO = new VO();
				vo.id = entity.@id;
				vo.type = entity.@type;
				this.vos[vo.id] = vo;
			}
		}
		
		private function loadDaos(daos:XMLList):void{
			var length:int = daos.length();
			for(var i:int=0;i<length;i++){
				/*
				<dao id="userdap" type="com.trainsmart.example.demo.model.UserDAO" vo="uservo"/>
				*/
				var entity:XML = daos[i];
				var dao:DAO = new DAO();
				dao.id =  entity.@id;
				dao.type = entity.@type;
				dao.vo =  entity.@vo;				
				
				this.daos[dao.id] = dao;
			}
		}
		private function loadControls(controls:XMLList):void{
			var length:int = controls.length();
			for(var i:int=0;i<length;i++){
				//<control id="adduser" type="com.trainsmart.example.demo.AddUserCtrl"/>
				var entity:XML = controls[i];
				var c:Control = new Control();
				c.id = entity.@id;
				c.type = entity.@type;
				c.auto = (entity.@auto=='true');
				this.controls[c.id] = c;		

			}
		}		
		
		private function onLoad():void{			
			var i:int = 0;
			//view
			for(var viewId:String in  views){
				var v:View = views[viewId] as View;
				var id:String = v.id;
				var voId:String = v.vo;
				var type:String = v.type;
				var properties:Array = v.properties;
				var ViewCl:Class = getDefinitionByName(type) as Class;
				var view:SmartForm = new ViewCl();
				if(voId=='')				
					view.init(_context,viewId,properties);
				else{
					var vo:VO = this.vos[voId];
					view.init(_context,viewId,properties,vo.type);
				}
				_context.registerView(id,view);
			}
			//control
			for(var controlId:String in controls){
				var meta:Control = controls[controlId] as Control;
				var controlId:String = meta.id;
				var Cl:Class = getDefinitionByName(meta.type) as Class;
				var inst:IControl = new Cl(_context);
				_context.registerControl(controlId,inst);
				if(meta.auto)
					_context.initRuns.push(controlId);
			}
			//model
			for(var daoId:String  in daos){
				
				var daometa:DAO = daos[daoId] as DAO;
				var vometa:VO = vos[daometa.vo] as VO;
				
				var DAOClass:Class = getDefinitionByName(daometa.type) as Class;
				var VOClass:Class = getDefinitionByName(vometa.type) as Class;
				var model:IModel = new DAOClass(VOClass);
				_context.registerModel(daometa.id, model); 
			}
			//flow
			//keep flow meata data into context metaflows
			var util:FlowUtil = new FlowUtil(_context);			
			util.metaflows = flows;
		}
		
		
		
	
	}
}